package com.xy.smartsms.manager;

import android.content.Context;
import android.graphics.drawable.BitmapDrawable;
import android.os.Handler;
import android.os.Looper;
import android.text.TextUtils;

import com.xy.smartsms.util.BitmapLoader;
import com.xy.smartsms.util.CommonUtils;
import com.xy.smartsms.util.Log;

import org.json.JSONObject;

import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

import cn.cmcc.online.smsapi.sdk.net.NetUtil;
import cn.cmcc.online.smsapi.sdk.util.DuoquUtils;
import cn.cmcc.online.smsapi.sdk.util.StringUtils;
import cn.cmcc.online.smsapi.util.ParseManager;
import cn.cmcc.online.smsapi.util.SdkCallBack;

public class PublicInfoManager {
    private static final String TAG = PublicInfoManager.class.getSimpleName();
    private static PublicInfoManager sPublicInfoManager = null;
    // key: pubid, value: pubinfo
    private HashMap<String, JSONObject> mPublicDataMap = new HashMap<String, JSONObject>();
    // key: phone, value: {pubid, purpose}
    private HashMap<String, String[]> mPhonePublicIdMap = new HashMap<String, String[]>();
    private ExecutorService mPublicInfoPool = Executors.newFixedThreadPool(1);
    private Handler mHandler = null;
    private Context mContext = null;
    private BitmapLoader mBitmapLoader = null;

    private void preload() {
        // only call once, so use new Thread other than thread pool
        new Thread(new Runnable() {
            @Override
            public void run() {
                Log.v(TAG, "run: start");
                Set<String> publicNumbers = DuoquUtils.getSdkDoAction().loadPublicNumbers(mContext);
                HashMap<String, String[]> phonePubMap = ParseManager.loadAllPubNum(publicNumbers);
                if (phonePubMap != null && !phonePubMap.isEmpty()) {
                    mPhonePublicIdMap.putAll(phonePubMap);

                    HashSet<String> pubIdSet = new HashSet<String>();
                    Iterator<String[]> iterator = phonePubMap.values().iterator();
                    while (iterator.hasNext()) {
                        String[] value = iterator.next();
                        if (value.length > 0) {
                            pubIdSet.add(value[0]);
                        }
                    }

                    HashMap<String, JSONObject> result = ParseManager.loadAllPubInfo(pubIdSet);
                    if (result != null && !result.isEmpty()) {
                        mPublicDataMap.putAll(result);
                    }
                }
                Log.i(TAG, "run: end");
            }
        }).start();
    }

    private PublicInfoManager(Context context) {
        mContext = context;
        mHandler = new Handler(Looper.getMainLooper());
        mBitmapLoader = BitmapLoader.getInstance(mContext);
        preload();
    }

    public static PublicInfoManager getInstance() {
        return sPublicInfoManager;
    }

    public static PublicInfoManager getInstance(Context context) {
        synchronized (PublicInfoManager.class) {
            if (sPublicInfoManager == null) {
                sPublicInfoManager = new PublicInfoManager(context);
            }
        }

        return sPublicInfoManager;
    }

    /**
     * 企业资料获取监听
     */
    public interface OnPublicInfoListener {
        /**
         * 企业资料准备好
         *
         * @param phone    企业号码
         * @param name     企业名称
         * @param drawable 企业logo
         */
        void onPublicInfo(String phone, String name, BitmapDrawable drawable, JSONObject data);
    }

    private void callbackPublicInfoSafe(final String phone,
                                        final OnPublicInfoListener listener,
                                        final String name,
                                        final BitmapDrawable drawable,
                                        final JSONObject data) {
        if (listener == null) {
            return;
        }

        if (CommonUtils.isMainThread()) {
            listener.onPublicInfo(phone, name, drawable, data);
        } else {
            mHandler.post(new Runnable() {
                @Override
                public void run() {
                    listener.onPublicInfo(phone, name, drawable, data);
                }
            });
        }
    }

    private void callbackPublicInfo(final String phone,
                                    final OnPublicInfoListener listener,
                                    final JSONObject json,
                                    final boolean loadAsync) {
        if (json != null) {
            final String name = json.optString("name");
            final String logo = json.optString("logoc");
            if (TextUtils.isEmpty(logo)) {
                callbackPublicInfoSafe(phone, listener, name, null, json);
                return;
            }

            BitmapLoader.ImageCallback callback = null;
            if (loadAsync) {
                callback = new BitmapLoader.ImageCallback() {
                    @Override
                    public void imageLoad(String url, final BitmapDrawable drawable) {
                        callbackPublicInfoSafe(phone, listener, name, drawable, json);
                    }
                };
            }

            BitmapDrawable drawable = getLogoDrawable(logo, callback);
            // update name in time even logo is not available
            callbackPublicInfoSafe(phone, listener, name, drawable, json);
        }
    }

    private synchronized void putPublicInfoDataInCache(String phone, JSONObject json) {
        if (TextUtils.isEmpty(phone) || json == null) {
            return;
        }

        String publicId = json.optString("id");
        if (TextUtils.isEmpty(publicId)) {
            return;
        }

        json.remove("classifyName");
        json.remove("classifyCode");
        json.remove("email");
        json.remove("weiboName");
        json.remove("weiboUrl");
        json.remove("weixin");
        json.remove("website");
        json.remove("moveWebSite");
        json.remove("pubnum");
        try {
            mPublicDataMap.put(publicId, json);

            String[] values = {publicId};
            mPhonePublicIdMap.put(phone, values);
        } catch (Throwable t) {
            Log.e(TAG, "putPublicInfoDataInCache", t);
        }
    }

    private JSONObject getPublicInfoDataInCache(String phone) {
        JSONObject json = null;
        String[] values = mPhonePublicIdMap.get(phone);
        if (values != null && values.length > 0) {
            String publicId = values[0];
            json = mPublicDataMap.get(publicId);
            if (values.length > 1) {
                String purpose = values[1];
                if (json != null && !TextUtils.isEmpty(purpose)) {
                    try {
                        json.put("purpose", purpose);
                    } catch (Throwable t) {
                        Log.e(TAG, "getPublicInfoDataInCache", t);
                    }
                }
            }
        }

        return json;
    }

    private void updatePhonePublicIdDataCache(String phone) {
        if (TextUtils.isEmpty(phone)) {
            return;
        }

        Log.i(TAG, "updatePhonePublicIdDataCache: " + phone);
        String[] values = mPhonePublicIdMap.get(phone);
        if (values != null && values.length > 0) {
            String publicId = values[0];
            if (!TextUtils.isEmpty(publicId)) {
                JSONObject json = mPublicDataMap.get(publicId);
                final String logo = json.optString("logoc");
                if (!TextUtils.isEmpty(logo)) {
                    removeLogo(logo);
                }

                mPublicDataMap.remove(publicId);
            }
        }

        mPhonePublicIdMap.remove(phone);
    }

    public void updatePhonePublicIdDataCache(List<String> list) {
        if (list == null || list.size() == 0) {
            return;
        }

        for (String phone : list) {
            updatePhonePublicIdDataCache(phone);
            // update public info in background
            loadPublicInfo(phone, null, true);
        }
    }

    private void getPublicInfoDataFromApi(final String phone,
                                          final OnPublicInfoListener listener) {
        Log.v(TAG, "getPublicInfoDataFromApi: " + phone);
        Map<String, String> extend = new HashMap<String, String>();
        extend.put("id", phone);
        ParseManager.queryPublicInfoWithId(mContext, phone, 1, "", extend, new SdkCallBack() {
            @Override
            public void execute(Object... obj) {
                try {
                    if (obj == null || obj.length <= 2) {
                        return;
                    }

                    String phoneCallback = (String) obj[2];
                    Integer status = (Integer) obj[0];
                    String result = (String) obj[1];
                    Log.i(TAG, "execute: phone=" + phoneCallback + " status=" + status + " result=" + result);
                    if (status == 0 && !StringUtils.isNull(result) && phone.equals(phoneCallback)) {
                        JSONObject json = new JSONObject(result);
                        putPublicInfoDataInCache(phoneCallback, json);
                        callbackPublicInfo(phone, listener, json, true);
                    }
                } catch (Throwable t) {
                    Log.e(TAG, "loadPublicInfo", t);
                }
            }
        });
    }

    /**
     * 获取企业资料
     *
     * @param phone     接入码
     * @param listener  回调
     * @param loadAsync 异步加载，如果是滑动中应该为false
     */

    public void loadPublicInfo(final String phone, final OnPublicInfoListener listener, boolean loadAsync) {
        final String formatNumber = CommonUtils.formatPhoneNum(phone);
        JSONObject data = getPublicInfoDataInCache(formatNumber);
        if (data != null) {
            callbackPublicInfo(phone, listener, data, loadAsync);
            return;
        }

        if (loadAsync) {
            mPublicInfoPool.execute(new Runnable() {
                @Override
                public void run() {
                    getPublicInfoDataFromApi(formatNumber, listener);
                }
            });
        }
    }

    private String getLogoKey(String logoName) {
        return logoName.substring(0, logoName.lastIndexOf("."));
    }

    private void removeLogo(String logoName) {
        mBitmapLoader.removeLogo(getLogoKey(logoName));
    }

    private BitmapDrawable getLogoDrawable(String logoName, BitmapLoader.ImageCallback callback) {
        String path = NetUtil.BIZPORT_DOWN_URL + logoName;
        return mBitmapLoader.loadBitmap(CommonUtils.hashKey(path), path, callback);
    }
}
